// Copyright (c) 2009 - Quildreen <quildreen@gmail.com>                     
//                                                                          
//  Permission is hereby granted, free of charge, to any person              
//  obtaining a copy of this software and associated documentation files     
//  (the "Software"), to deal in the Software without restriction,           
//  including without limitation the rights to use, copy, modify, merge,     
//  publish, distribute, sublicense, and/or sell copies of the Software,     
//  and to permit persons to whom the Software is furnished to do so,        
//  subject to the following conditions:                                     
//                                                                           
//  The above copyright notice and this permission notice shall be           
//  included in all copies or substantial portions of the Software.          
//                                                                           
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       
//  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                    
//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE   
//  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION   
//  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION    
//  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 


/**
 * lily.graphics.font
 *
 * Abstracts font rendering in javascript.
 **/
lily.defineModule("graphics.font");

/**
 * class lily.graphics.Font
 * 
 * Abstract system-level font rendering.
 **/
lily.graphics.Font = Class.create(
{
    /**
     * new lily.graphics.Font(name[, options])
     * - name (String): unique identifier for this font.
     * - options (Object): optional rendering arguments.
     **/
    initialize: function(name)
    {
        var options = Object.extend({
            face: null,
            bold_font: null,
            italic_font: null,
            bold_italic_font: null,

            size: 12,
            colour: '#000000',
            letter_spacing: null,
            line_height: 1,
            word_wrap: false,
            text_align: "left",

            // wheter we should register this font automatically
            register: true
        }, arguments[1]);

        /**
         * lily.graphics.Font#name -> String
         * 
         * The alias of the font for the manager.
         **/
        this.name = name;

        /**
         * lily.graphics.Font#font -> String
         * 
         * The font face to use for this font. The format used by this
         * variable (as all face ones) is internal -- it can be a String with
         * the system font name, or an object mapping the characters position
         * in a image.
         **/
        this.font = options.face;

        /**
         * lily.graphics.Font#bold_font -> String
         * 
         * The font face to use for this font. The format used by this
         * variable (as all face ones) is internal -- it can be a String with
         * the system font name, or an object mapping the characters position
         * in a image.
         **/
        this.bold_font = options.bold_font;

        /**
         * lily.graphics.Font#italic_font -> String
         * 
         * The font face to use for this font. The format used by this
         * variable (as all face ones) is internal -- it can be a String with
         * the system font name, or an object mapping the characters position
         * in a image.
         **/
        this.italic_font = options.italic_font;

        /**
         * lily.graphics.Font#bold_italic_font -> String
         * 
         * The font face to use for this font. The format used by this
         * variable (as all face ones) is internal -- it can be a String with
         * the system font name, or an object mapping the characters position
         * in a image.
         **/
        this.bold_italic_font = options.bold_italic_font;

        /**
         * lily.graphics.Font#size -> Number
         * 
         * The current (and default) size of this font. This will be used
         * as default option in rendering.
         **/
        this.size = options.size;
        
        /**
         * lily.graphics.Font#letter_spacing -> Number
         * 
         * The amount of spacing to use between letters, in pixels.
         **/
        this.letter_spacing = options.letter_spacing;

        /**
         * lily.graphics.Font#line_height -> Number
         * 
         * The size of each line, in percentage.
         **/
        this.line_height = options.line_height;

        /**
         * lily.graphics.Font#word_wrap -> Boolean
         * 
         * Whether or not to use word wrapping.
         **/
        this.word_wrap = options.word_wrap;

        /**
         * lily.graphics.Font#bold -> Boolean
         * 
         * Whether or not to render the text in bold.
         **/
        this.bold = false;

        /**
         * lily.graphics.Font#italic -> Boolean
         * 
         * Whether or not to render the text in italic.
         **/
        this.italic = false;
        
        /**
         * lily.graphics.Font#underline -> Boolean
         * 
         * Whether or not to render the text with an underline.
         **/
        this.underline = false;
        
        /**
         * lily.graphics.Font#overline -> Boolean
         * 
         * Whether or not to render the text with an overline.
         **/
        this.overline = false;
        
        /**
         * lily.graphics.Font#strike -> Boolean
         * 
         * Whether or not to render the text with a strike through.
         **/
        this.strike = false;

        /**
         * lily.graphics.Font#colour -> String
         * 
         * The colour in which the text should be rendered, as a CSS
         * colour string.
         **/
        this.colour = options.colour;

        /**
         * lily.graphics.Font#text_align -> String
         * 
         * The horizontal alignment of the text.
         **/
        this.text_align = options.text_align;


        if (options.register) {
            lily.graphics.font.register(this, this.name);
        }
    },

    /**
     * lily.graphics.Font#render(text[, surface][, options]) -> lily.graphics.Surface
     * - text (String): the text to render.
     * - surface ([[lily.graphics.Surface]]) - surface to render the text to.
     * - options (Object) - additional rendering options. 
     * 
     * Renders the given text to the given surface. If no surface is provided,
     * one will be created.
     **/
    render: function(text, surface, options)
    {
        /* void */
    }
});

/*--
 * Manages different kinds of fonts (system and image-based).
 */
Object.extend(lily.graphics.font, (function() {
    // A dictionary of non-system fonts handled by this object.
    var fonts = {};

    /**
     * lily.graphics.font.register(font[, name]) -> undefined
     * - font (Font): font object to register.
     * - name (String): in which name the font should be registered.
     * 
     * Register a new font in the font manager.
     * 
     * If a font name is not given, it'll be extracted from the Font object.
     **/
    function register(font, name)
    {
        name || (name = font.name);
        fonts[name] = font;
    }

    /**
     * lily.graphics.font.remove(name) -> undefined
     * - name (String): name of the font to remove.
     * 
     * Removes a previously registered font from the manager. Throws an error
     * if the font is not registered.
     **/
    function remove(name)
    {
        if (fonts[name]) {
            delete fonts[name];
        } else {
            throw new EFontNotRegistered();
        }
    }

    /**
     * lily.graphics.font.get(name) -> Font
     * - name (String): name of the font to retrive.
     * 
     * Returns the font registered with the given name.
     **/
    function get(name)
    {
        if (fonts[name]) {
            return fonts[name];
        } else {
            throw new EFontNotRegistered();
        }
    }

    /**
     * lily.graphics.font.render(text[, font][, surface][, options]) -> lily.graphics.Surface
     * - text (String): text to render
     * - font (String | Font): font to use as rendering.
     * - surface ([[lily.graphics.Surface]]): surface to render the text to.
     * - options (Object): additional rendering options.
     * 
     * Render the given text with the specified font.
     * 
     * If a font is not given, the function will use the module's
     * default font ([[lily.graphics.font.default_font]]) instead.
     * 
     * If a surface is not given, one'll be created and returned.
     * 
     * The rendering options accepts the same properties you can pass
     * when creating a [[lily.graphics.Font]] object.
     **/
    function render(text, font, surface, options)
    {
        // gets the default font if one wasn't specified
        font || (font = lily.graphics.font.default_font);
        
        if (Object.isString(font)) {
            font = fonts[font];
        }
        if (!font) {
            throw new EFontNotRegistered();
        }

        // render the font
        return font.render(text, surface, options);
    }

    return {
        /**
         * lily.graphics.font.default_font -> String | Font
         * 
         * The font to use in rendering when one is not provided.
         **/
        default_font: '',

        register: register,
        remove: remove,
        get: get,
        render: render
    };
}()));